// 公共窗口创建器
import { BrowserWindow, BrowserWindowConstructorOptions, ipcMain, shell, screen } from "electron";
import { is } from '@electron-toolkit/utils'
import { join } from 'path'
import { getPosition, setPostion } from './storageUtils'

interface WindowPosition {
  x: number
  y: number
}

interface WindowBound extends WindowPosition {
  width: number
  height: number
}

export class CommonWindow {
  private win: BrowserWindow | null = null

  // 计时器
  movingInterval: ReturnType<typeof setInterval> | null = null;

  // 窗口最终位置
  winBound: WindowBound = {
    x: 0,
    y: 0,
    width: 0,
    height: 0
  }

  constructor(param: BrowserWindowConstructorOptions, defaultPosition?: WindowPosition, url?: String) {
    if (param.width) this.winBound.width = param.width
    if (param.height) this.winBound.height = param.height
    if (defaultPosition) {
      this.winBound.x = defaultPosition.x
      this.winBound.y = defaultPosition.y
    }
    this.init(param, url)
  }

  // 初始化
  init(param: BrowserWindowConstructorOptions, url?: String) {
    this.win = new BrowserWindow({
      ...param,
      webPreferences: {
        preload: join(__dirname, '../preload/index.js'),
        sandbox: false, // true会导致无法使用node
        // experimentalFeatures: true, // 启用实验特性
      },
    })
    // 阻止弹出新窗口
    this.win.webContents.setWindowOpenHandler((details) => {
      shell.openExternal(details.url)
      return { action: 'deny' }
    })
    if (param.alwaysOnTop) {
      // 设置窗口优先级始终在最上方
      this.win.setAlwaysOnTop(true, 'screen-saver')
    }
    // 设置窗口对应的页面
    let winUrl = ''
    if (url) {
      winUrl += "/sub-win/" + url
    }
    if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
      this.win!.loadURL(process.env['ELECTRON_RENDERER_URL'] + "/#" + winUrl)
    } else {
      this.win!.loadFile(join(__dirname, '../renderer/index.html'), {
        hash: winUrl
      })
    }
    // this.win.webContents.openDevTools() // 打开开发者工具
  }

  // 初始化窗口位置
  initWinPosition(storageStr?: String) {
    const { width, height } = screen.getPrimaryDisplay().workAreaSize;
    if (storageStr) {
      const localPos = getPosition(storageStr)
      if (localPos && localPos.x !== 0 && localPos.y !== 0) {
        const x = localPos.x < width && localPos.x > 0 ? localPos.x : width - this.winBound.width - 20
        const y = localPos.y < height && localPos.y > 0 ? localPos.y : height - this.winBound.height - 40
        this.win!.setBounds({
          ...localPos,
          x,
          y
        }, true)
        return
      }
    }
    this.winBound.x = width - this.winBound.width - 20
    this.winBound.y = height - this.winBound.height - 40
    this.win!.setBounds(this.winBound, true)
  }

  // 窗口移动事件
  winMoveEventListener(storageStr: String) {
    ipcMain.on("window-move-open", (event, canMoving) => {
      if (!this.win) return
      // 窗口开始移动位置
      let winStartPosition = {
        x: 0,
        y: 0,
        width: this.winBound.width,
        height: this.winBound.height
      }
      // 鼠标开始位置
      let mouseStartPosition = {
        x: 0,
        y: 0
      }
      // 判断一下是不是主窗口，以防其他窗口也可以按住拖动
      const win = BrowserWindow.fromWebContents(event.sender)!
      if (win !== this.win) return
      if (canMoving) {
        // 开始移动
        // 读取原位置和窗口大小
        const bounds = this.win.getBounds();
        winStartPosition = {
          x: bounds.x,
          y: bounds.y,
          width: bounds.width,
          height: bounds.height
        }
        // 获取鼠标开始位置
        mouseStartPosition = screen.getCursorScreenPoint();
        // 鼠标位置和窗口位置的差值
        const gapX = mouseStartPosition.x - winStartPosition.x
        const gapY = mouseStartPosition.y - winStartPosition.y
        // 清除延时
        if (this.movingInterval) {
          clearInterval(this.movingInterval)
        }
        // 新建延时
        this.movingInterval = setInterval(() => {
          const cursorPosition = screen.getCursorScreenPoint()
          const moveX = cursorPosition.x - gapX
          const moveY = cursorPosition.y - gapY
          if (moveX === winStartPosition.x && moveY === winStartPosition.y) return // 鼠标没有移动，不执行任何操作
          // 如果windows系统设置的缩放比例不是100%时，只修改位置，会导致窗口大小发生变化，因此需要一并设置窗口大小，缺点是，这样会导致拖动时窗口抖动，暂时没有更好的解决办法
          this.winBound.x = moveX
          this.winBound.y = moveY
          this.win!.setBounds(this.winBound, true)
        }, 20)
      } else {
        // 清除延时，结束移动
        if (this.movingInterval !== null) {
          clearInterval(this.movingInterval)
        }
        this.movingInterval = null
        // 将窗口最终的位置返回给前端保存
        setPostion(storageStr, JSON.stringify(this.winBound))
      }
    })
  }

  // 打开窗口
  show() {
    if (this.win) {
      this.win.on('ready-to-show', () => {
        this.win!.show()
      })
    }
  }

  // 获取窗口
  getWindow() {
    return this.win
  }

  // 窗口图标是否再系统任务栏中显示
  setSkipTaskbar(flag: boolean) {
    if (this.win) {
      this.win.setSkipTaskbar(flag)
    }
  }

}


